import pygame
import random
from game_items import *
from game_hud import *
from game_music import *

class Game(object):
    """游戏类"""
    def __init__(self):
        # 游戏主窗口
        self.main_window = pygame.display.set_mode(SCREEN_RECT.size)
        pygame.display.set_caption("飞机大战")

        # 游戏状态属性
        self.is_game_over = False  # 游戏结束标记
        self.is_pause = False      # 游戏暂停标记

        # 精灵组属性
        self.all_group = pygame.sprite.Group()  # 所有精灵组
        self.enemies_group = pygame.sprite.Group()  # 敌机精灵组
        self.enemies_group = pygame.sprite.Group()  # 敌机精灵组
        self.supplies_group = pygame.sprite.Group()  # 道具精灵组
        # 创建精灵
        # 背景精灵,向下方移动
        GameSprite("background.png", 1, self.all_group)

        # 背景精灵,交替滚动
        self.all_group.add(Background(False), Background(True))

        # 英雄精灵,静止不动
        self.hero = Plane(1000, 5, 0, "me_down.wav", ["me%d.png" % i for i in range(1, 3)],
                    "me1.png", ["me_destroy_%d.png" % i for i in range(1, 5)],
                    self.all_group)
        # hero = Plane(["me%d.png" % i for i in range(1, 3)], self.all_group)
        # hero = GameSprite("me1.png", 0, self.all_group)
        self.hero.rect.center = SCREEN_RECT.center  # 显示在屏幕中央

        # 指示器面板
        self.hud_panel = HudPanel(self.all_group)

        # 创建敌机
        self.create_enemies()

        #创建道具
        self.create_supplies()

        #英雄精灵
        self.hero = Hero(self.all_group)

        #设置面板中炸弹数量
        self.hud_panel.show_bomb(self.hero.bomb_count)

        # TODO:将所有敌机的速度设置为 0，并修改敌机的初始位置
        for enemy in self.enemies_group.sprites():
          enemy.speed = 0
          enemy.rect.y += 400
        self.hero.speed = 1 


        #TODO 测试 - 音乐和音效
        # 加载背景音乐文件准备播放
        pygame.mixer.music.load("../res/sound/game_music.ogg")
        # 播放音乐


        #TODO 测试 - 音乐和音效
        # 测创建声音对象
        hero_down_sound = pygame.mixer.Sound("../res/sound/me_down.wav")
        hero_down_sound.play()


       # 创建音乐播放器
        self.player = MusicPlayer("game_music.ogg")
        self.player.play_music()




    def reset_game(self):
             """重置游戏"""
             self.is_game_over = False  # 游戏结束标记
             self.is_pause = False      # 游戏暂停标记

             self.hud_panel.reset_panel()      #重置指示器面板

             #设置英雄飞机的初始位置
             self.hero.rect.midbottom = HERO_DEFAULT_MTD_BOTTOM

             #清空所有敌机
             for enemy in self.enemies_group:
                 enemy.kill()
             #清空残留子弹
             for bullet in self.hero.bullets_group:
                 bullet.kill()
             #重新创建敌机
             self.create_enemies()




def event_handler(self):
    """事件监听
    :return:如果监听到退出事件,返回true,否则返回False
    """
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            return True
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: 
            return True
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            if self.is_game_over:                  # 游戏已经结束
                self.reset_game()                  # 重新开始游戏
            else:
                self.is_pause = not self.is_pause  # 切换暂停状态

            #暂停或恢复背景音乐
            self.player.pause_music(self.is_pause)

            #判断是否正在游戏
        if not self.is_game_over and not self.is_pause:

            #监听结束子弹增强效果定时器事件
            if event.type == BULLET_ENHANCED_OFF_EVENT:
              self.hero.bullets_kind = 0
              pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT, 0)

            #监听投放道具事件
            if event.type == THROW_SUPPLY_EVENT:
              self.player.play_sound("supply.wav")
              supply = random.choice(self.supplies_group.sprites())
              supply.throw_supply()

            #监听发射子弹事件
            if event.type == HERO_FIRE_EVENT:
             self.player.play_sound("supply.wav")
             self.hero.fire(self.all_group)



            #监听取消英雄飞机的无敌状态
            if event.type == HERO_POWER_OFF_EVENT:
              print("取消无敌状态...")
            #设置英雄飞机状态
            self.hero.is_power = False
             #取消定时器
            pygame.time.set_timer(HERO_POWER_OFF_EVENT, 0)  
          
          
            #监听结束子弹增强效果定时器事件
            if event.type == BULLET_ENHANCED_OFF_EVENT:
               self.hero.bullets_kind = 0
               pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT, 0)


            #监听英雄飞机牺牲事件
            if event.type == HERO_DEAD_EVENT:
              print("英雄牺牲了...")
              #生命计数 -1
              self.hud_panel.lives_count -= 1
              #更新生命计数显示
              self.hud_panel.show_lives()
              #更新炸弹显示
              self.hud_panel.show_bomb(self.hero.bomb_count)


            #监听玩家按下"b"键,引爆1颗炸弹
            if event.type == pygame.KEYDOWN and event.key == pygame.K_b:

              #如果英雄飞机没有牺牲同时有炸弹
              if self.hero.hp > 0 and self.hero.bomb_count > 0:
                self.player.play_sound("use_bomb.wav")


              # 引爆炸弹
              score = self.hero.blowup(self.enemies_group)
              # 更新炸弹数量变化
            #  TODO 测试炸弹数量变化(#  TODO...表示待完成项目提醒)
            self.hud_panel.show_bomb(random.randint(0, 100))
            self.hud_panel.show_bomb(self.hero.bomb_count)
               # 更新游戏得分
            if self.hud_panel.increase_score(score):
                self.create_enemies()

            # TOOD 测试生命计数数量变化
            self.hud_panel.lives_count  =random.randint(0, 10)
            self.hud_panel.show_lives()

            # TODO 测试炸弹摧毁所有敌机
            for enemy in self.enemies_group.sprites():
              enemy.hp = 0

    return False
def start(self):
  """开始游戏"""
  clock = pygame.time.Clock()         # 游戏时钟
  while True:


      #      # TODO模拟英雄飞机受到伤害
      self.hero.hp -= 30

      # 修改逐帧动画计数器
      frame_counter = (frame_counter + 1) % FRAME_INTERVAL
      # 更新all_group中所有精灵内容
      # self.all_group.update(frame_counter == 0)
      self.all_group.update(frame_counter == 0, move_hor, move_ver)
      

      # 生命计数等于0,表示游戏结束
      self.is_game_over = self.hud_panel.lives_count == 0
      if self.event_handler():        # 事件监听
          self.hud_panel.save_best_score()
          return

  #判断游戏状态
      if self.is_game_over:
        self.hud_panel.panel_pause(True, self.all_group)
      elif self.is_pause:
        self.hud_panel.panel_pause(False, self.all_group)
      else:
        self.hud_panel.panel_resume(self.all_group) 
        
      #碰撞检测
        self.check_collide()

     # 获取当前时刻的按键元组 
        keys = pygame.key.get_pressed()
     # 判断是否按下右方向键
        if keys[pygame.K_RIGHT]:
         self.hero.rect.x += 10

      # 水平移动基数    
        move_hor = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]

     # 垂直移动基数
        move_ver = keys[pygame.K_DOWN] - keys[pygame.K_UP]


    #   if self.is_game_over:
    #       print("游戏已经结束,按空格键重新开始...")
    #   elif self.is_pause:
    #       print("游戏已经暂停,按空格键继续...")
    #   else:

  #测试修改游戏得分
        # if self.hud_panel.increase_score(100):
        #   print("升级到 %d" % self.hud_panel.level)
        #   self.create_enemies() 
          
        # 更新all_group中所有精灵内容
        self.all_group.update()

        print("游戏进行中...")           
      pygame.display.update()         # 更新显示
      clock.tick(60)                  # 设置刷新帧率


def create_enemies(self):
    """根据关卡级别创建不同数量的敌机"""
    # 敌机精灵组中的精灵数量
    count = len(self.enemies_group.sprites())
    # 要添加到的精灵组
    groups = (self.all_group, self.enemies_group)
    # 判断关卡级别及已有的敌机数量
    if self.hud_panel.level == 1 and count == 0:  # 关卡级别1
      for i in range(16):
           Enemy(0, 3, *groups)
    elif self.hud_panel.level == 2 and count == 16:  # 关卡级别2
       # 提高敌机的最大速度
      for enemy in self.enemies_group.sprites():
          enemy.max_speed = 5
       # 创建敌机
      for i in range(8):
        Enemy(0, 5, *groups)
      for i in range(2):
        Enemy(1, 1, *groups)
    elif self.hud_panel.level == 3 and count == 26:  # 关卡级别3
        # 提高敌机的最大速度
      for enemy in self.enemies_group.sprites():
          enemy.max_speed = 7 if enemy.kind == 0 else 3
        # 创建敌机
      for i in range(8):
         Enemy(0, 7, *groups)
      for i in range(2):
         Enemy(1, 3, *groups)
      for i in range(2):
         Enemy(2, 1, *groups) 

def check_collide(self):
      """碰撞检测"""
      # 检测英雄飞机和敌机的碰撞
      # collide_enemies = pygame.sprite.spritecollide(self.hero,
      #                                               self.enemies_group,False,None)
      # collide_enemies = pygame.sprite.spritecollide(self.hero,
      #                                                 self.enemies_group, False,
      #                                                 pygame.sprite.collide_mask) 


      # 检测英雄飞机和敌机的碰撞,若处于无敌状态,彼此不能碰撞
      if not self.hero.is_power:
        enemies = pygame.sprite.spritecollide(self.hero, self.enemies_group, False,
                                                      pygame.sprite.collide_mask)

      #是否撞到敌机
      if enemies:

        #播放英雄飞机被撞毁音效
        self.player.play_sound(self.hero.wav_name)
        self.hero.hp = 0            #英雄被摧毁


        self.hero.hp = 0                #英雄被摧毁
        for enemy in enemies:
          enemy.hp = 0                #敌机同样被炸毁

      
      # 过滤掉已经摧毁的敌机
      enemies = list(filter(lambda x: x.hp > 0, enemies))

                                 

      # for enemy in collide_enemies:
      #   enemy.hp = 0                     #摧毁发生碰撞的敌机

      # 检测敌机是否被子弹击中
      hit_enemies = pygame.sprite.groupcollide(self.enemies_group, self.hero.bullets_group,
                                                 False, False, pygame.sprite.collide_mask)
            
      # 遍历字典
      for enemy in hit_enemies:
          # 已经被摧毁的敌机，不需要浪费子弹
          if enemy.hp <= 0:  
             continue
      # 遍历击中敌机的子弹列表
      for bullet in hit_enemies[enemy]:
        # 将子弹从所有精灵组中清除
        bullet.kill()
        # 修改敌机生命值
        enemy.hp -= bullet.damage
        #如果敌机没有被摧毁，继续判定下一课子弹
        if enemy.hp > 0:
          continue
        # 修改游戏得分并判断是否升级
        if self.hud_panel.increase_score(enemy.value):
          self.create_enemies()
          #播放升级音效
          self.player.play_sound("upgrade.wav")
          self.create_enemies()
        #播放敌机爆炸音效
          self.player.play_sound(enemy.wav_name)

        # 退出遍历子弹列表循环
        break
      #英雄拾取道具
      supplies = pygame.sprite.spritecollide(self.hero, self.supplies_group,
                                             False, pygame.sprite.collide_mask)
      if supplies:
        supply = supplies[0]
        #播放拾取道具音效
        self.player.play_sound(supply.wav_name)
        #将道具设置到游戏窗口下方
        supply.rect.y = SCREEN_RECT.h
        #判断道具类型
        if supply.kind == 0:                    #设置炸弹补给
          self.hero.bomb_count += 1
          self.hud_panel.show_bomb(self.hero.bomb_count)
        else:
            self.hero.bullets_kind = 1          #设置子弹增强
            #设置结束
            pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT, 8000)
      


def create_supplies(self):
  """创建道具"""
  Supply(0, self.supplies_group, self.all_group)
  Supply(1, self.supplies_group, self.all_group)
  #设置30s投放道具定时器事件（测试时用10s）
  pygame.time.set_timer(THROW_SUPPLY_EVENT, 10000)






if __name__ == '__main__':
       pygame.init()
       Game().start()
       pygame.quit()    


